"""A collection of all commands that a Kanna can use to interact with the game."""

from src.common import config, settings, utils
import time
import math
from src.routine.components import Command
from src.common.vkeys import press, key_down, key_up


# List of key mappings
class Key:
    # Movement
    JUMP = 'c'
    主攻 = "a"
    瞬移 = 's'

    # Buffs
    花狐 = "f5"
    紫光白狐 = 'f4'
    大鬼封魂阵 = 'f3'
    雪女 = 'f2'
    晓之阵 = 'f1'


    # Skills
    妖绘释放 = "q"
    夜叉召喚 = 'r'
    天狗 = 'e'
    鬼踏奸 = 'd'
    灵石召唤 = 'f'
    破魔阵 = 'g'
    迎式神 = "b"
    恢復靈力 = "h"
    除靈符 = 'v'

#########################
#       Commands        #
#########################
def step(direction, target):
    """
    Performs one movement step in the given DIRECTION towards TARGET.
    Should not press any arrow keys, as those are handled by Auto Maple.
    """
    print(target)
    num_presses = 2
    if direction == 'up' or direction == 'down':
        num_presses = 1
    if config.stage_fright and direction != 'up' and utils.bernoulli(0.75):
        time.sleep(utils.rand_float(0.1, 0.3))
    d_y = target[1] - config.player_pos[1]
    if abs(d_y) > settings.move_tolerance * 1.5:
        if direction == 'down':
            press(Key.JUMP, 3)
        elif direction == 'up':
            press(Key.JUMP, 1)
    press(Key.瞬移, num_presses)
    # time.sleep(0.03)
    # press(Key.主攻,1)


class Adjust(Command):
    """Fine-tunes player position using small movements."""

    def __init__(self, x, y, max_steps=5):
        super().__init__(locals())
        self.target = (float(x), float(y))
        self.max_steps = settings.validate_nonnegative_int(max_steps)

    def main(self):
        counter = self.max_steps
        toggle = True
        error = utils.distance(config.player_pos, self.target)
        while config.enabled and counter > 0 and error > settings.adjust_tolerance:
            if toggle:
                d_x = self.target[0] - config.player_pos[0]
                threshold = settings.adjust_tolerance / math.sqrt(2)
                if abs(d_x) > threshold:
                    walk_counter = 0
                    if d_x < 0:
                        key_down('left')
                        while config.enabled and d_x < -1 * threshold and walk_counter < 60:
                            time.sleep(0.05)
                            walk_counter += 1
                            d_x = self.target[0] - config.player_pos[0]
                        key_up('left')
                    else:
                        key_down('right')
                        while config.enabled and d_x > threshold and walk_counter < 60:
                            time.sleep(0.05)
                            walk_counter += 1
                            d_x = self.target[0] - config.player_pos[0]
                        key_up('right')
                    counter -= 1
            else:
                d_y = self.target[1] - config.player_pos[1]
                if abs(d_y) > settings.adjust_tolerance / math.sqrt(2):
                    if d_y < 0:
                        瞬移('up').main()
                    else:
                        key_down('down')
                        time.sleep(0.05)
                        press(Key.JUMP, 3, down_time=0.1)
                        key_up('down')
                        time.sleep(0.05)
                    counter -= 1
            error = utils.distance(config.player_pos, self.target)
            toggle = not toggle


class Buff(Command):
    """Uses each of Kanna's buffs once. Uses 'Haku Reborn' whenever it is available."""

    def __init__(self):
        super().__init__(locals())
        self.huahu_time = 0
        # self.buff_time = 0

    def main(self):
        buffs = [Key.花狐]
        now = time.time()
        if self.huahu_time == 0 or now - self.huahu_time > 150:
            press(Key.花狐, 2)
            self.huahu_time = now

        # if self.buff_time == 0 or now - self.buff_time > settings.buff_cooldown:
        #     for key in buffs:
        #         press(key, 3, up_time=0.3)
        #     self.buff_time = now


class 瞬移(Command):
    """
    瞬移s in a given direction, jumping if specified. Adds the player's position
    to the current Layout if necessary.
    """

    def __init__(self, direction, jump='False'):
        super().__init__(locals())
        self.direction = settings.validate_arrows(direction)
        self.jump = settings.validate_boolean(jump)

    def main(self):
        num_presses = 3
        time.sleep(0.05)
        if self.direction in ['up', 'down']:
            num_presses = 2
        if self.direction != 'up':
            key_down(self.direction)
            time.sleep(0.05)
        if self.jump:
            if self.direction == 'down':
                press(Key.JUMP, 3, down_time=0.1)
            else:
                press(Key.JUMP, 1)
        if self.direction == 'up':
            key_down(self.direction)
            time.sleep(0.05)
        press(Key.瞬移, num_presses)
        key_up(self.direction)
        if settings.record_layout:
            config.layout.add(*config.player_pos)


class 迎式神(Command):
    """Attacks using 'Shikigami Haunting' in a given direction."""

    def __init__(self, direction, attacks=2, repetitions=1):
        super().__init__(locals())
        self.direction = settings.validate_horizontal_arrows(direction)
        self.attacks = int(attacks)
        self.repetitions = int(repetitions)

    def main(self):
        time.sleep(0.05)
        key_down(self.direction)
        time.sleep(0.05)
        if config.stage_fright and utils.bernoulli(0.7):
            time.sleep(utils.rand_float(0.1, 0.3))
        for _ in range(self.repetitions):
            press(Key.迎式神, self.attacks, up_time=0.05)
        key_up(self.direction)
        if self.attacks > 2:
            time.sleep(0.3)
        else:
            time.sleep(0.2)

class 恢復靈力(Command):
    """Uses 'Tengu Strike' once."""

    def __init__(self, duration=16):
        super().__init__(locals())
        self.duration = settings.validate_nonnegative_int(duration)
        self.time = 0

    def main(self):
        kills = [Key.恢復靈力]
        now = time.time()
        if self.time == 0 or now - self.time > self.duration:
            for key in kills:
                press(key, 1, up_time=0.3)
            self.time = now

class 天狗(Command):
    """Uses 'Tengu Strike' once."""

    def __init__(self, duration=180):
        super().__init__(locals())
        self.duration = settings.validate_nonnegative_int(duration)
        self.tiangou_time = 0

    def main(self):

        kills = [Key.天狗]
        now = time.time()
        if self.tiangou_time == 0 or now - self.tiangou_time > self.duration:
            for key in kills:
                press(key, 1, up_time=0.3)
            self.tiangou_time = now



class 晓之阵(Command):
    """Uses 'Tengu Strike' once."""

    def __init__(self, duration=120):
        super().__init__(locals())
        self.duration = settings.validate_nonnegative_int(duration)
        self.time = 0

    def main(self):
        kills = [Key.晓之阵]
        now = time.time()
        if self.time == 0 or now - self.time > self.duration:
            for key in kills:
                press(key, 1, up_time=0.3)
            self.time = now

class 主攻(Command):
    """Attacks using 'Shikigami Haunting' in a given direction."""

    def __init__(self, direction=None, 攻擊次數=1, 重複次數=1):
        super().__init__(locals())
        self.direction = settings.validate_horizontal_arrows(direction)
        self.attacks = int(攻擊次數)
        self.repetitions = int(重複次數)

    def main(self):
        time.sleep(0.05)
        key_down(self.direction)
        time.sleep(0.05)
        if config.stage_fright and utils.bernoulli(0.7):
            time.sleep(utils.rand_float(0.1, 0.3))
        for _ in range(self.repetitions):
            press(Key.主攻, self.attacks, up_time=0.05)
        key_up(self.direction)
        if self.attacks > 2:
            time.sleep(0.3)
        else:
            time.sleep(0.2)

class 紫光白狐(Command):
    """Uses 'Tengu Strike' once."""

    def __init__(self, duration=180):
        super().__init__(locals())
        self.duration = settings.validate_nonnegative_int(duration)
        self.time = 0

    def main(self):
        kills = [Key.紫光白狐]
        now = time.time()
        if self.time == 0 or now - self.time > self.duration:
            for key in kills:
                press(key, 2, up_time=0.3)
            self.time = now

class 妖绘释放(Command):
    """Uses 'Tengu Strike' once."""

    def __init__(self, duration=91):
        super().__init__(locals())
        self.duration = settings.validate_nonnegative_int(duration)
        self.time = 0

    def main(self):
        kills = [Key.妖绘释放]
        now = time.time()
        if self.time == 0 or now - self.time > self.duration:
            for key in kills:
                press(key, 2, up_time=0.3)
            self.time = now


class 鬼踏奸(Command):
    """Uses 'Tengu Strike' once."""
    def __init__(self, duration=120):
        super().__init__(locals())
        self.duration = settings.validate_nonnegative_int(duration)
        self.time = 0

    def main(self):
        kills = [Key.鬼踏奸]
        now = time.time()
        if self.time == 0 or now - self.time > self.duration:
            for key in kills:
                press(key, 2, up_time=0.3)
            self.time = now

class 雪女(Command):
    """Uses 'Tengu Strike' once."""
    def __init__(self, duration=80):
        super().__init__(locals())
        self.duration = settings.validate_nonnegative_int(duration)
        self.time = 0

    def main(self):
        kills = [Key.雪女]
        now = time.time()
        if self.time == 0 or now - self.time > self.duration:
            for key in kills:
                time.sleep(0.2)
                press(key, 2, up_time=0.3)
            self.time = now


class 大鬼封魂阵(Command):
    """Uses 'Tengu Strike' once."""

    def __init__(self, duration=180):
        super().__init__(locals())
        self.duration = settings.validate_nonnegative_int(duration)
        self.time = 0

    def main(self):
        kills = [Key.大鬼封魂阵]
        now = time.time()
        if self.time == 0 or now - self.time > self.duration:
            for key in kills:
                time.sleep(0.2)
                press(key, 2, up_time=0.3)
            self.time = now

class 破魔阵(Command):
    """Uses 'Tengu Strike' once."""

    def __init__(self, duration=180):
        super().__init__(locals())
        self.duration = settings.validate_nonnegative_int(duration)
        self.time = 0

    def main(self):
        kills = [Key.破魔阵]
        now = time.time()
        if self.time == 0 or now - self.time > self.duration:
            for key in kills:
                time.sleep(0.2)
                press(key, 2, up_time=0.3)
            self.time = now


class 灵石召唤(Command):
    """Uses 'Tengu Strike' once."""

    def __init__(self, duration=220):
        super().__init__(locals())
        self.duration = settings.validate_nonnegative_int(duration)
        self.time = 0

    def main(self):
        kills = [Key.灵石召唤]
        now = time.time()
        if self.time == 0 or now - self.time > self.duration:
            for key in kills:
                time.sleep(0.2)
                press(key, 2, up_time=0.3)
            self.time = now


class 清醒靈魂(Command):
    """
    Places 'Lucid Soul Summon' in a given direction, or towards the center of the map if
    no direction is specified.
    """

    def __init__(self, direction=None):
        super().__init__(locals())
        if direction is None:
            self.direction = direction
        else:
            self.direction = settings.validate_horizontal_arrows(direction)

    def main(self):
        if self.direction:
            press(self.direction, 1, down_time=0.1, up_time=0.05)
        else:
            if config.player_pos[0] > 0.5:
                press('left', 1, down_time=0.1, up_time=0.05)
            else:
                press('right', 1, down_time=0.1, up_time=0.05)
        press(Key.清醒靈魂, 3)


class 夜叉召喚(Command):
    """
    Places 'Ghost Yaksha Boss' in a given direction, or towards the center of the map if
    no direction is specified.
    """

    def __init__(self, direction=None,duration=30):
        super().__init__(locals())
        self.duration = settings.validate_nonnegative_int(duration)
        self.time = 0
        if direction is None:
            self.direction = direction
        else:
            self.direction = settings.validate_horizontal_arrows(direction)

    def main(self):
        now = time.time()
        if self.direction:
            if self.time == 0 or now - self.time > self.duration:
                press(self.direction, 1, down_time=0.1, up_time=0.05)
                press(Key.夜叉召喚, 1)
                self.time = now
        else:

            if self.time == 0 or now - self.time > self.duration:
                if config.player_pos[0] > 0.5:
                    press('left', 1, down_time=0.1, up_time=0.05)
                else:
                    press('right', 1, down_time=0.1, up_time=0.05)
                press(Key.夜叉召喚, 1)
                self.time = now



class 除靈符(Command):
    """Uses 'Exorcist's Charm' once."""

    def __init__(self, jump='False'):
        super().__init__(locals())
        self.jump = settings.validate_boolean(jump)

    def main(self):
        if self.jump:
            press(Key.JUMP, 1, down_time=0.1, up_time=0.15)
        press(Key.除靈符, 2, up_time=0.05)

